home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 028a / unzup41e.zip / FILE_IO.C < prev    next >
C/C++ Source or Header  |  1991-05-13  |  24KB  |  817 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   file_io.c
  4.  
  5.   This file contains routines for doing direct input/output, file-related
  6.   sorts of things.
  7.  
  8.   ---------------------------------------------------------------------------*/
  9.  
  10.  
  11. #include "unzip.h"
  12.  
  13.  
  14. /************************************/
  15. /*  File_IO Includes, Defines, etc. */
  16. /************************************/
  17.  
  18. #ifdef VMS
  19. #include <rms.h>                /* RMS prototypes, error codes, etc. */
  20. #include <ssdef.h>              /* system services error codes */
  21. #include <descrip.h>            /* "descriptor" format stuff */
  22. #endif
  23.  
  24. static int WriteBuffer __((int fd, unsigned char *buf, int len));
  25. static int dos2unix __((unsigned char *buf, int len));
  26.  
  27. int CR_flag = 0;        /* when last char of buffer == CR (for dos2unix()) */
  28.  
  29.  
  30.  
  31.  
  32.  
  33. /*******************************/
  34. /*  Function open_input_file() */
  35. /*******************************/
  36.  
  37. int open_input_file()
  38. {                               /* return non-0 if open failed */
  39.     /*
  40.      *  open the zipfile for reading and in BINARY mode to prevent cr/lf
  41.      *  translation, which would corrupt the bitstreams
  42.      */
  43.  
  44. #ifndef UNIX
  45.     zipfd = open(zipfn, O_RDONLY | O_BINARY);
  46. #else
  47.     zipfd = open(zipfn, O_RDONLY);
  48. #endif
  49.     if (zipfd < 1) {
  50.         fprintf(stderr, "error:  can't open zipfile [ %s ]\n", zipfn);
  51.         return (1);
  52.     }
  53.     return 0;
  54. }
  55.  
  56.  
  57.  
  58.  
  59.  
  60. /************************/
  61. /*  Function readbuf()  */
  62. /************************/
  63.  
  64. int readbuf(buf, size)
  65. char *buf;
  66. register unsigned size;
  67. {                               /* return number of bytes read into buf */
  68.     register int count;
  69.     int n;
  70.  
  71.     n = size;
  72.     while (size) {
  73.         if (incnt == 0) {
  74.             if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0)
  75.                 return (n-size);
  76.             /* buffer ALWAYS starts on a block boundary:  */
  77.             cur_zipfile_bufstart += INBUFSIZ;
  78.             inptr = inbuf;
  79.         }
  80.         count = min(size, incnt);
  81.         memcpy(buf, inptr, count);
  82.         buf += count;
  83.         inptr += count;
  84.         incnt -= count;
  85.         size -= count;
  86.     }
  87.     return (n);
  88. }
  89.  
  90.  
  91.  
  92.  
  93.  
  94. #ifdef VMS
  95.  
  96. /**********************************/
  97. /*  Function create_output_file() */
  98. /**********************************/
  99.  
  100. int create_output_file()
  101. {                               /* return non-0 if sys$create failed */
  102.     /*
  103.      * VMS VERSION (generic version is below)
  104.      *
  105.      * Create the output file and set its date/time using VMS Record Management
  106.      * Services From Hell.  Then reopen for appending with normal Unix/C-type
  107.      * I/O functions.  This is the EASY way to set the file date/time under VMS.
  108.      */
  109.     int ierr, yr, mo, dy, hh, mm, ss;
  110.     char timbuf[24];            /* length = first entry in "stupid" + 1 */
  111.     struct FAB fileblk;
  112.     struct XABDAT dattim;
  113.     static char *month[] =
  114.     {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  115.      "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  116. /*  fixed-length string descriptor (why not just a pointer to timbuf? sigh.) */
  117.     struct dsc$descriptor stupid =
  118.     {23, DSC$K_DTYPE_T, DSC$K_CLASS_S, timbuf};
  119.  
  120.  
  121.  
  122. /*---------------------------------------------------------------------------
  123.     First initialize the necessary RMS and date/time variables.  "FAB" stands
  124.     for "file attribute block," "XAB" for "extended attribute block."  Files
  125.     under VMS are usually in "variable-length records" format with "carriage-
  126.     return carriage control" (at least for text files).  Unfortunately, some-
  127.     where along the line extra "carriage returns" (i.e., line feed characters)
  128.     get stuck in files which are opened in the variable format.  This may be
  129.     a VMS problem, an RMS problem, or a Unix/C I/O problem, but every 8192
  130.     characters of text file is followed by a spurious LF, and more often than
  131.     that for binary files.  So we use the stream-LF format instead (which is
  132.     what the Unix/C I/O routines do by default).  EDT complains about such
  133.     files but goes ahead and edits them; TPU (Adam, Eve) and vi don't seem
  134.     to care at all.
  135.   ---------------------------------------------------------------------------*/
  136.  
  137.     yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + 1980; /* dissect date */
  138.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
  139.     dy = (lrec.last_mod_file_date & 0x1f);
  140.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;        /* dissect time */
  141.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  142.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  143.  
  144.     fileblk = cc$rms_fab;               /* fill FAB with default values */
  145.     fileblk.fab$l_fna = filename;       /* l_fna, b_fns are the only re- */
  146.     fileblk.fab$b_fns = strlen(filename); /*  quired user-supplied fields */
  147.     fileblk.fab$b_rfm = FAB$C_STMLF;    /* stream-LF record format */
  148.     fileblk.fab$b_rat = FAB$M_CR;       /* carriage-return carriage ctrl */
  149.     /*                      ^^^^ *NOT* V_CR!!!     */
  150.     fileblk.fab$l_xab = &dattim;        /* chain XAB to FAB */
  151.     dattim = cc$rms_xabdat;             /* fill XAB with default values */
  152.  
  153.     CR_flag = 0;                /* Hack to get CR at end of buffer working
  154.                                    (dos2unix) */
  155.  
  156. /*---------------------------------------------------------------------------
  157.     Next convert date into an ASCII string, then use a VMS service to con-
  158.     vert the string into internal time format.  Obviously this is a bit of a
  159.     kludge, but I have absolutely NO intention of figuring out how to convert
  160.     MS-DOS time into tenths of microseconds elapsed since freaking 17 Novem-
  161.     ber 1858!!  Particularly since DEC doesn't even have a native 64-bit data
  162.     type.  Bleah.
  163.   ---------------------------------------------------------------------------*/
  164.  
  165.     sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", dy, month[mo], yr,
  166.             hh, mm, ss);
  167.  
  168. /*  "xab$q_cdt" is the XAB field which holds the file's creation date/time */
  169.     sys$bintim(&stupid, &dattim.xab$q_cdt);
  170.  
  171. /*---------------------------------------------------------------------------
  172.     Next create the file under RMS.  If sys$create chokes with an error of
  173.     RMS$_SYN (syntax error), it's probably because a Unix-style directory was
  174.     specified, so try to create the file again using the regular creat() func-
  175.     tion (date/time won't be set properly in this case, obviously).
  176.   ---------------------------------------------------------------------------*/
  177.  
  178.     if ((ierr = sys$create(&fileblk)) != RMS$_NORMAL)
  179.         if (ierr == RMS$_SYN) { /* try Unix/C create:  0 = default perms */
  180.             outfd = creat(filename, 0, "rfm=stmlf", "rat=cr");
  181.             if (outfd < 1) {
  182.                 fprintf(stderr, "Can't create output file:  %s\n", filename);
  183.                 return (1);
  184.             } else {
  185.                 return (0);
  186.             }
  187.         } else {                /* probably access violation */
  188.             fprintf(stderr, "Can't create output file:  %s\n", filename);
  189.             return (1);
  190.         }
  191.  
  192. /*---------------------------------------------------------------------------
  193.     Finally, close the file under RMS and reopen with Unix/C open() function.
  194.   ---------------------------------------------------------------------------*/
  195.  
  196.     sys$close(&fileblk);
  197.     outfd = open(filename, O_RDWR);
  198.  
  199.     return (0);
  200. }
  201.  
  202.  
  203.  
  204.  
  205.  
  206. #else                           /* !VMS */
  207.  
  208. /**********************************/
  209. /*  Function create_output_file() */
  210. /**********************************/
  211.  
  212. int create_output_file()
  213. {                               /* return non-0 if creat failed */
  214.     /*
  215.      * GENERIC VERSION (special VMS version is above)
  216.      *
  217.      * Create the output file with default permissions.
  218.      */
  219.     extern int do_all;
  220.     char answerbuf[10];
  221.     UWORD holder;
  222.  
  223.  
  224.  
  225.     CR_flag = 0;                /* Hack to get CR at end of buffer working. */
  226.  
  227.     /*
  228.      * check if the file exists, unless do_all
  229.      */
  230.     if (!do_all) {
  231.         outfd = open(filename, 0);
  232.         if (outfd >= 0) {       /* first close it, before you forget! */
  233.             close(outfd);
  234.  
  235.             /* ask the user before blowing it away */
  236.             fprintf(stderr, "replace %s, y-yes, n-no, a-all: ", filename);
  237.             fgets(answerbuf, 9, stdin);
  238.  
  239.             switch (answerbuf[0]) {
  240.             case 'y':
  241.             case 'Y':
  242.                 break;
  243.             case 'a':
  244.             case 'A':
  245.                 do_all = 1;
  246.                 break;
  247.             case 'n':
  248.             case 'N':
  249.             default:
  250.                 while (ReadByte(&holder));
  251.                 return 1;       /* it's done! */
  252.             }
  253.         }
  254.     }
  255. #ifndef UNIX
  256.     outfd = creat(filename, (S_IWRITE | S_IREAD) & f_attr);
  257. #else
  258.     {
  259.       int mask;
  260.       mask = umask(0);
  261.       outfd = creat(filename, 0777 & f_attr);
  262.       umask(mask);
  263.     }
  264. #endif
  265.  
  266.     if (outfd < 1) {
  267.         fprintf(stderr, "Can't create output: %s\n", filename);
  268.         return 1;
  269.     }
  270.     /*
  271.      * close the newly created file and reopen it in BINARY mode to
  272.      * disable all CR/LF translations
  273.      */
  274. #ifndef UNIX
  275. #ifdef THINK_C
  276.     /*
  277.      * THINKC's stdio routines have the horrible habit of
  278.      * making any file you open look like generic files
  279.      * this code tells the OS that it's a text file
  280.      */
  281.     if (aflag) {
  282.         fileParam pb;
  283.         OSErr err;
  284.  
  285.         CtoPstr(filename);
  286.         pb.ioNamePtr = filename;
  287.         pb.ioVRefNum = 0;
  288.         pb.ioFVersNum = 0;
  289.         pb.ioFDirIndex = 0;
  290.         err = PBGetFInfo(&pb,0);
  291.         if (err == noErr) {
  292.             pb.ioFlFndrInfo.fdCreator = '????';
  293.             pb.ioFlFndrInfo.fdType = 'TEXT';
  294.             err = PBSetFInfo(&pb, 0);
  295.         }
  296.         PtoCstr(filename);
  297.     }
  298. #endif
  299.     if (!aflag) {
  300.         close(outfd);
  301.         outfd = open(filename, O_RDWR | O_BINARY);
  302.     }
  303. #endif
  304.     return 0;
  305. }
  306.  
  307. #endif                          /* !VMS */
  308.  
  309.  
  310.  
  311.  
  312.  
  313. /*****************************/
  314. /*  Function FillBitBuffer() */
  315. /*****************************/
  316.  
  317. int FillBitBuffer(bits)
  318. register int bits;
  319. {
  320.     /*
  321.      * Get the bits that are left and read the next UWORD.  This
  322.      * function is only used by the READBIT macro (which is used
  323.      * by all of the uncompression routines).
  324.      */
  325.     register int result = bitbuf;
  326.     UWORD temp;
  327.     int sbits = bits_left;
  328.  
  329.  
  330.     bits -= bits_left;
  331.  
  332.     /* read next UWORD of input */
  333.     bits_left = ReadByte(&bitbuf);
  334.     bits_left += ReadByte(&temp);
  335.  
  336.     bitbuf |= (temp << 8);
  337.     if (bits_left == 0)
  338.         zipeof = 1;
  339.  
  340.     /* get the remaining bits */
  341.     result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
  342.     bitbuf >>= bits;
  343.     bits_left -= bits;
  344.     return result;
  345. }
  346.  
  347.  
  348.  
  349.  
  350.  
  351. /************************/
  352. /*  Function ReadByte() */
  353. /************************/
  354.  
  355. int ReadByte(x)
  356. UWORD *x;
  357. {
  358.     /*
  359.      * read a byte; return 8 if byte available, 0 if not
  360.      */
  361.  
  362.  
  363.     if (csize-- <= 0)
  364.         return 0;
  365.  
  366.     if (incnt == 0) {
  367.         if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0)
  368.             return 0;
  369.         /* buffer ALWAYS starts on a block boundary:  */
  370.         cur_zipfile_bufstart += INBUFSIZ;
  371.         inptr = inbuf;
  372.     }
  373.     *x = *inptr++;
  374.     --incnt;
  375.     return 8;
  376. }
  377.  
  378.  
  379.  
  380. #ifdef FLUSH_AND_WRITE
  381. /***************************/
  382. /*  Function FlushOutput() */
  383. /***************************/
  384.  
  385. int FlushOutput()
  386. {                               /* return PK-type error code */
  387.     /* flush contents of output buffer */
  388.     /*
  389.      * This combined version doesn't work, and I sure can't see why not...
  390.      * probably something stupid, but how much can you screw up in 6 lines???
  391.      * [optimization problem??]
  392.      */
  393.     int len;
  394.  
  395.  
  396.     if (outcnt) {
  397.         UpdateCRC(outbuf, outcnt);
  398.  
  399.         if (!tflag) {
  400.             if (aflag)
  401.                 len = dos2unix(outbuf, outcnt);
  402.             if (write(outfd, outout, len) != len) {
  403.                 fprintf(stderr, "Fatal write error.\n");
  404.                 return (50);    /* 50:  disk full */
  405.             }
  406.         }
  407.         outpos += outcnt;
  408.         outcnt = 0;
  409.         outptr = outbuf;
  410.     }
  411.     return (0);                 /* 0:  no error */
  412. }
  413.  
  414. #else                           /* separate flush and write routines */
  415. /***************************/
  416. /*  Function FlushOutput() */
  417. /***************************/
  418.  
  419. int FlushOutput()
  420. {                               /* return PK-type error code */
  421.     /* flush contents of output buffer */
  422.     if (outcnt) {
  423.         UpdateCRC(outbuf, outcnt);
  424.  
  425.         if (!tflag && WriteBuffer(outfd, outbuf, outcnt))
  426.             return (50);        /* 50:  disk full */
  427.  
  428.         outpos += outcnt;
  429.         outcnt = 0;
  430.         outptr = outbuf;
  431.     }
  432.     return (0);                 /* 0:  no error */
  433. }
  434.  
  435. /***************************/
  436. /*  Function WriteBuffer() */
  437. /***************************/
  438.  
  439. static int WriteBuffer(fd, buf, len)    /* return 0 if successful, 1 if not */
  440. int fd;
  441. unsigned char *buf;
  442. int len;
  443. {
  444.     if (aflag)
  445.         len = dos2unix(buf, len);
  446.     if (write(fd, outout, len) != len) {
  447. #ifdef DOS_OS2
  448.         if (!cflag) {           /* ^Z treated as EOF, removed with -c */
  449. #endif
  450.             fprintf(stderr, "Fatal write error.\n");
  451.             return (1);         /* FAILED */
  452. #ifdef DOS_OS2
  453.         }
  454. #endif
  455.     }
  456.     return (0);
  457. }
  458.  
  459. #endif
  460.  
  461.  
  462.  
  463.  
  464. /************************/
  465. /*  Function dos2unix() */
  466. /************************/
  467.  
  468. static int dos2unix(buf, len)
  469. unsigned char *buf;
  470. int len;
  471. {
  472.     int new_len;
  473.     int i;
  474.     unsigned char *walker;
  475.  
  476.     new_len = len;
  477.     walker = outout;
  478. #ifdef MACOS
  479.     /*
  480.      * Mac wants to strip LFs instead CRs from CRLF pairs
  481.      */
  482.     if (CR_flag && *buf == LF) {
  483.         buf++;
  484.         new_len--;
  485.         len--;
  486.         CR_flag = buf[len] == CR;
  487.     }
  488.     else
  489.         CR_flag = buf[len - 1] == CR;
  490.     for (i = 0; i < len; i += 1) {
  491.         *walker++ = ascii_to_native(*buf);
  492.         if (*buf == LF) walker[-1] = CR;
  493.         if (*buf++ == CR && *buf == LF) {
  494.             new_len--;
  495.             buf++;
  496.             i++;
  497.         }
  498.     }
  499. #else
  500.     if (CR_flag && *buf != LF)
  501.         *walker++ = ascii_to_native(CR);
  502.     CR_flag = buf[len - 1] == CR;
  503.     for (i = 0; i < len; i += 1) {
  504.         *walker++ = ascii_to_native(*buf);
  505.         if (*buf++ == CR && *buf == LF) {
  506.             new_len--;
  507.             walker[-1] = ascii_to_native(*buf++);
  508.             i++;
  509.         }
  510.     }
  511.     /*
  512.      * If the last character is a CR, then "ignore it" for now...
  513.      */
  514.     if (walker[-1] == ascii_to_native(CR))
  515.         new_len--;
  516. #endif
  517.     return new_len;
  518. }
  519.  
  520.  
  521.  
  522.  
  523.  
  524. #ifdef DOS_OS2
  525.  
  526. /***************************************/
  527. /*  Function set_file_time_and_close() */
  528. /***************************************/
  529.  
  530. void set_file_time_and_close()
  531.  /*
  532.   * MS-DOS AND OS/2 VERSION (Mac, Unix versions are below)
  533.   *
  534.   * Set the output file date/time stamp according to information from the
  535.   * zipfile directory record for this member, then close the file.  This
  536.   * is optional and can be deleted if your compiler does not easily support
  537.   * setftime().
  538.   */
  539. {
  540. /*---------------------------------------------------------------------------
  541.     Allocate local variables needed by OS/2 and Turbo C.  [OK, OK, so it's
  542.     a bogus comment...but this routine was getting way too cluttered and
  543.     needed some visual separators.  Bleah.]
  544.   ---------------------------------------------------------------------------*/
  545.  
  546. #ifdef OS2              /* (assuming only MSC or MSC-compatible compilers
  547.                          * for this part) */
  548.  
  549.     union {
  550.         FDATE fd;               /* system file date record */
  551.         UWORD zdate;            /* date word */
  552.     } ud;
  553.  
  554.     union {
  555.         FTIME ft;               /* system file time record */
  556.         UWORD ztime;            /* time word */
  557.     } ut;
  558.  
  559.     FILESTATUS fs;
  560.  
  561. #else                           /* !OS2 */
  562. #ifdef __TURBOC__
  563.  
  564.     union {
  565.         struct ftime ft;        /* system file time record */
  566.         struct {
  567.             UWORD ztime;        /* date and time words */
  568.             UWORD zdate;        /* .. same format as in .ZIP file */
  569.         } zt;
  570.     } td;
  571.  
  572. #endif                          /* __TURBOC__ */
  573. #endif                          /* !OS2 */
  574.  
  575.     /*
  576.      * Do not attempt to set the time stamp on standard output
  577.      */
  578.     if (cflag) {
  579.         close(outfd);
  580.         return;
  581.     }
  582.  
  583.  
  584. /*---------------------------------------------------------------------------
  585.     Copy and/or convert time and date variables, if necessary; then set the
  586.     file time/date.
  587.   ---------------------------------------------------------------------------*/
  588.  
  589. #ifdef OS2
  590.  
  591.     DosQFileInfo(outfd, 1, &fs, sizeof(fs));
  592.     ud.zdate = lrec.last_mod_file_date;
  593.     fs.fdateLastWrite = ud.fd;
  594.     ut.ztime = lrec.last_mod_file_time;
  595.     fs.ftimeLastWrite = ut.ft;
  596.     DosSetFileInfo(outfd, 1, &fs, sizeof(fs));
  597.  
  598. #else                           /* !OS2 */
  599. #ifdef __TURBOC__
  600.  
  601.     td.zt.ztime = lrec.last_mod_file_time;
  602.     td.zt.zdate = lrec.last_mod_file_date;
  603.     setftime(outfd, &td.ft);
  604.  
  605. #else                           /* !__TURBOC__:  MSC MS-DOS */
  606.  
  607.     _dos_setftime(outfd, lrec.last_mod_file_date, lrec.last_mod_file_time);
  608.  
  609. #endif                          /* !__TURBOC__ */
  610. #endif                          /* !OS2 */
  611.  
  612. /*---------------------------------------------------------------------------
  613.     And finally we can close the file...at least everybody agrees on how to
  614.     do *this*.  I think...
  615.   ---------------------------------------------------------------------------*/
  616.  
  617.     close(outfd);
  618. }
  619.  
  620.  
  621.  
  622.  
  623.  
  624. #else                           /* !DOS_OS2 ... */
  625. #ifndef VMS                     /* && !VMS (already done) ... */
  626. #ifndef MTS                     /* && !MTS (can't do):  Mac or UNIX */
  627. #ifdef MACOS                    /* Mac first */
  628.  
  629. /***************************************/
  630. /*  Function set_file_time_and_close() */
  631. /***************************************/
  632.  
  633. void set_file_time_and_close()
  634.  /*
  635.   * MAC VERSION
  636.   *
  637.   * First close the output file, then set its date/time stamp according
  638.   * to information from the zipfile directory record for this file.  [So
  639.   * technically this should be called "close_file_and_set_time()", but
  640.   * this way we can use the same prototype for either case, without extra
  641.   * #ifdefs.  So there.]
  642.   */
  643. {
  644.     long m_time;
  645.     DateTimeRec dtr;
  646.     ParamBlockRec pbr;
  647.     OSErr err;
  648.  
  649.     if (outfd != 1)
  650.     {
  651.         close(outfd);
  652.  
  653.         /*
  654.          * Macintosh bases all file modification times on the number of seconds
  655.          * elapsed since Jan 1, 1904, 00:00:00.  Therefore, to maintain
  656.          * compatibility with MS-DOS archives, which date from Jan 1, 1980,
  657.          * with NO relation to GMT, the following conversions must be made:
  658.          *      the Year (yr) must be incremented by 1980;
  659.          *      and converted to seconds using the Mac routine Date2Secs(),
  660.          *      almost similar in complexity to the Unix version :-)
  661.          *                                     J. Lee
  662.          */
  663.  
  664.         dtr.year = (((lrec.last_mod_file_date >> 9) & 0x7f) + 1980); /* dissect date */
  665.         dtr.month = ((lrec.last_mod_file_date >> 5) & 0x0f);
  666.         dtr.day = (lrec.last_mod_file_date & 0x1f);
  667.  
  668.         dtr.hour = ((lrec.last_mod_file_time >> 11) & 0x1f);      /* dissect time */
  669.         dtr.minute = ((lrec.last_mod_file_time >> 5) & 0x3f);
  670.         dtr.second = ((lrec.last_mod_file_time & 0x1f) * 2);
  671.         Date2Secs(&dtr, &m_time);
  672.         CtoPstr(filename);
  673.         pbr.fileParam.ioNamePtr = filename;
  674.         pbr.fileParam.ioVRefNum = pbr.fileParam.ioFVersNum = pbr.fileParam.ioFDirIndex = 0;
  675.         err = PBGetFInfo(&pbr, 0L);
  676.         pbr.fileParam.ioFlMdDat = pbr.fileParam.ioFlCrDat = m_time;
  677.         if (err == noErr) {
  678.             err = PBSetFInfo(&pbr, 0L);
  679.         }
  680.         if (err != noErr) {
  681.             printf("Error, can't set the time for %s\n",filename);
  682.         }
  683.  
  684.         /* set read-only perms if needed */
  685.         if (err != noErr && f_attr != 0) {
  686.             err = SetFLock(filename, 0);
  687.         }
  688.         PtoCstr(filename);
  689.     }
  690. }
  691.  
  692.  
  693.  
  694.  
  695.  
  696. #else                           /* !MACOS:  only one left is UNIX */
  697.  
  698. /***************************************/
  699. /*  Function set_file_time_and_close() */
  700. /***************************************/
  701.  
  702. void set_file_time_and_close()
  703.  /*
  704.   * UNIX VERSION (MS-DOS & OS/2, Mac versions are above)
  705.   *
  706.   * First close the output file, then set its date/time stamp according
  707.   * to information from the zipfile directory record for this file.  [So
  708.   * technically this should be called "close_file_and_set_time()", but
  709.   * this way we can use the same prototype for either case, without extra
  710.   * #ifdefs.  So there.]
  711.   */
  712. {
  713.     long m_time;
  714.     int yr, mo, dy, hh, mm, ss, leap, days = 0;
  715.     struct utimbuf {
  716.       time_t atime;             /* New access time */
  717.       time_t mtime;             /* New modification time */
  718.     } tp;
  719. #ifdef BSD
  720.     static struct timeb tbp;
  721. #else
  722.     extern long timezone;
  723. #endif
  724.  
  725.  
  726.     close(outfd);
  727.  
  728.     if (cflag)                  /* can't set time on stdout */
  729.         return;
  730.  
  731.     /*
  732.      * These date conversions look a little weird, so I'll explain.
  733.      * UNIX bases all file modification times on the number of seconds
  734.      * elapsed since Jan 1, 1970, 00:00:00 GMT.  Therefore, to maintain
  735.      * compatibility with MS-DOS archives, which date from Jan 1, 1980,
  736.      * with NO relation to GMT, the following conversions must be made:
  737.      *      the Year (yr) must be incremented by 10;
  738.      *      the Date (dy) must be decremented by 1;
  739.      *      and the whole mess must be adjusted by TWO factors:
  740.      *          relationship to GMT (ie.,Pacific Time adds 8 hrs.),
  741.      *          and whether or not it is Daylight Savings Time.
  742.      * Also, the usual conversions must take place to account for leap years,
  743.      * etc.
  744.      *                                     C. Seaman
  745.      */
  746.  
  747.     yr = (((lrec.last_mod_file_date >> 9) & 0x7f) + 10); /* dissect date */
  748.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f);
  749.     dy = ((lrec.last_mod_file_date & 0x1f) - 1);
  750.  
  751.     hh = ((lrec.last_mod_file_time >> 11) & 0x1f);      /* dissect time */
  752.     mm = ((lrec.last_mod_file_time >> 5) & 0x3f);
  753.     ss = ((lrec.last_mod_file_time & 0x1f) * 2);
  754.  
  755.     /* leap = # of leap years from 1970 up to but not including
  756.        the current year */
  757.  
  758.     leap = ((yr + 1969) / 4);   /* Leap year base factor */
  759.  
  760.     /* How many days from 1970 to this year? */
  761.     days = (yr * 365) + (leap - 492);
  762.  
  763.     switch (mo) {               /* calculate expired days this year */
  764.     case 12:
  765.         days += 30;
  766.     case 11:
  767.         days += 31;
  768.     case 10:
  769.         days += 30;
  770.     case 9:
  771.         days += 31;
  772.     case 8:
  773.         days += 31;
  774.     case 7:
  775.         days += 30;
  776.     case 6:
  777.         days += 31;
  778.     case 5:
  779.         days += 30;
  780.     case 4:
  781.         days += 31;
  782.     case 3:
  783.         days += 28;             /* account for leap years (2000 IS one) */
  784.         if (((yr + 1970) % 4 == 0) && (yr + 1970) != 2100)  /* OK thru 2199 */
  785.             ++days;
  786.     case 2:
  787.         days += 31;
  788.     }
  789.  
  790.     /* convert date & time to seconds relative to 00:00:00, 01/01/1970 */
  791.     m_time = ((days + dy) * 86400) + (hh * 3600) + (mm * 60) + ss;
  792.  
  793. #ifdef BSD
  794.    ftime(&tbp);
  795.    m_time += tbp.timezone * 60L;
  796. #else                                   /* !BSD */
  797.     tzset();                            /* Set `timezone'. */
  798.     m_time += timezone;                 /* account for timezone differences */
  799. #endif
  800.  
  801.     if (localtime(&m_time)->tm_isdst)
  802.         m_time -= 60L * 60L;            /* Adjust for daylight savings time */
  803.  
  804.     /* set the time stamp on the file */
  805.     
  806.     tp.mtime = m_time;                  /* Set modification time */
  807.     tp.atime = m_time;                  /* Set access time */
  808.  
  809.     if (utime(filename, &tp))
  810.         fprintf(stderr, "Error, can't set the time for %s\n",filename);
  811. }
  812.  
  813. #endif                          /* ?MACOS */
  814. #endif                          /* ?MTS */
  815. #endif                          /* ?VMS */
  816. #endif                          /* ?DOS_OS2 */
  817.